home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / misc1 / iv26_w30.zip / SOURCES / PROPSHEE.C < prev    next >
C/C++ Source or Header  |  1992-02-04  |  13KB  |  595 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. /*
  24.  * Property sheet management.
  25.  */
  26.  
  27. #include <InterViews/propsheet.h>
  28. #include <InterViews/strpool.h>
  29. #include <InterViews/strtable.h>
  30. #include <ctype.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33.  
  34. extern StringTable* nameTable;
  35.  
  36. PropertySheet* properties;
  37.  
  38. static StringPool* propvalues;
  39.  
  40. class PropList {
  41.     friend class PropDir;
  42.     friend class PropertySheet;
  43. protected:
  44.     PropertyName name;
  45.     PropList* next;
  46.     PropList* prev;
  47.  
  48.     PropList();
  49.     PropList(PropertyName);
  50.     virtual ~PropList();
  51.  
  52.     void Append(PropList*);
  53.     void DeleteAll();
  54.     PropList* Find(PropertyName);
  55.     void Remove();
  56. };
  57.  
  58. class AttrList : public PropList {
  59.     friend class PropDir;
  60.     friend class PropertySheet;
  61.  
  62.     PropertyValue value;
  63.     PropertyType type;
  64.  
  65.     AttrList();
  66.     AttrList(PropertyName);
  67.  
  68.     boolean FindAttr(PropertyDef&);
  69. };
  70.  
  71. class DirList : public PropList {
  72.     friend class PropDir;
  73.     friend class PropertySheet;
  74.  
  75.     PropDir* info;
  76.  
  77.     DirList();
  78.     DirList(PropertyName);
  79.     ~DirList();
  80.  
  81.     boolean FindSubDir(PropertyName, PropDir*&);
  82. };
  83.  
  84. class PropDir {
  85. public:
  86.     PropDir();
  87.     ~PropDir();
  88. private:
  89.     friend class PropertySheet;
  90.  
  91.     PropDir* parent;
  92.     AttrList* attrs;
  93.     DirList* dirs;
  94.     AttrList* vattrs;
  95.     DirList* vdirs;
  96.  
  97.     PropDir* MakeDirs(const char*&);
  98. };
  99.  
  100. static const int pathClusterSize = 20;
  101.  
  102. class PropPathElement {
  103.     friend class PropertySheet;
  104.  
  105.     PropDir* dir;
  106.     boolean sibling;
  107. };
  108.  
  109. class PropPath {
  110.     friend class PropertySheet;
  111.  
  112.     PropPathElement element[pathClusterSize];
  113.     PropPathElement* top;
  114.     PropPath* next;
  115.     PropPath* prev;
  116.  
  117.     PropPath();
  118. };
  119.  
  120. static char* Strdup (const char* str, int n) {
  121.     char* s = new char[n+1];
  122.     strncpy(s, str, n);
  123.     s[n] = '\0';
  124.     return s;
  125. }
  126.  
  127. /*
  128.  * class PropList
  129.  */
  130.  
  131. PropList::PropList () {
  132.     name = nil;
  133.     next = this;
  134.     prev = this;
  135. }
  136.  
  137. PropList::PropList (PropertyName n) {
  138.     name = n;
  139. }
  140.  
  141. PropList::~PropList () {
  142.     /* nothing to do */
  143. }
  144.  
  145. void PropList::Append (PropList* p) {
  146.     p->next = prev->next;    /* link element to old tail->next */
  147.     p->prev = prev;        /* link element to old tail */
  148.     prev->next = p;        /* link old tail to element */
  149.     prev = p;            /* set tail to element */
  150. }
  151.  
  152. void PropList::Remove () {
  153.     next->prev = prev;
  154.     prev->next = next;
  155. }
  156.  
  157. PropList* PropList::Find (PropertyName n) {
  158.     register PropList* p;
  159.  
  160.     for (p = next; p != this; p = p->next) {
  161.     if (p->name == n) {
  162.         return p;
  163.     }
  164.     }
  165.     return nil;
  166. }
  167.  
  168. void PropList::DeleteAll () {
  169.     register PropList* p, * pnext;
  170.  
  171.     for (p = next; p != this; p = pnext) {
  172.     pnext = p->next;
  173.     delete p;
  174.     }
  175.     next = this;
  176.     prev = this;
  177. }
  178.  
  179. /*
  180.  * class AttrList
  181.  */
  182.  
  183. AttrList::AttrList () {
  184.     value = nil;
  185.     type = nil;
  186. }
  187.  
  188. AttrList::AttrList (PropertyName n) : (n) {
  189.     value = nil;
  190.     type = nil;
  191. }
  192.  
  193. boolean AttrList::FindAttr (register PropertyDef& p) {
  194.     register AttrList* a;
  195.  
  196.     for (a = (AttrList*)next; a != this; a = (AttrList*)a->next) {
  197.     if (a->name == p.name) {
  198.         p.type = a->type;
  199.         p.value = a->value;
  200.         return true;
  201.     }
  202.     }
  203.     return false;
  204. }
  205.  
  206. /*
  207.  * class DirList
  208.  */
  209.  
  210. DirList::DirList () {
  211.     info = nil;
  212. }
  213.  
  214. DirList::DirList (PropertyName n) : (n) {
  215.     info = new PropDir;
  216. }
  217.  
  218. boolean DirList::FindSubDir (PropertyName n, PropDir*& subdir) {
  219.     register DirList* d;
  220.  
  221.     for (d = (DirList*)next; d != this; d = (DirList*)d->next) {
  222.     if (d->name == n) {
  223.         subdir = d->info;
  224.         return true;
  225.     }
  226.     }
  227.     return false;
  228. }
  229.  
  230. DirList::~DirList () {
  231.     delete info;
  232. }
  233.  
  234. /*
  235.  * class PropDir
  236.  */
  237.  
  238. PropDir::PropDir () {
  239.     parent = nil;
  240.     attrs = new AttrList;
  241.     dirs = new DirList;
  242.     vattrs = new AttrList;
  243.     vdirs = new DirList;
  244. }
  245.  
  246. PropDir::~PropDir () {
  247.     dirs->DeleteAll();
  248.     delete dirs;
  249.     vdirs->DeleteAll();
  250.     delete vdirs;
  251.     attrs->DeleteAll();
  252.     delete attrs;
  253.     vattrs->DeleteAll();
  254.     delete vattrs;
  255. }
  256.  
  257. PropDir* PropDir::MakeDirs (const char*& name) {
  258.     register const char* p;
  259.     PropDir* dir;
  260.     DirList* cur, * sub;
  261.     PropertyName n;
  262.     int c;
  263.  
  264.     dir = this;
  265.     c = '.';
  266.     for (p = name; *p != '\0'; p++) {
  267.     if (*p == '.' || *p == '*') {
  268.         if (p > name) {
  269.         n = nameTable->Id(name, p - name);
  270.         cur = (c == '*') ? dir->vdirs : dir->dirs;
  271.         if (!cur->FindSubDir(n, dir)) {
  272.             sub = new DirList(n);
  273.             sub->info->parent = dir;
  274.             cur->Append(sub);
  275.             dir = sub->info;
  276.         }
  277.         }
  278.         c = *p;
  279.         name = p + 1;
  280.     }
  281.     }
  282.     return dir;
  283. }
  284.  
  285. /*
  286.  * class PropPath
  287.  */
  288.  
  289. PropPath::PropPath () {
  290.     top = &element[0];
  291.     next = nil;
  292.     prev = nil;
  293. }
  294.  
  295. /*
  296.  * class PropertySheet
  297.  */
  298.  
  299. PropertySheet::PropertySheet () {
  300.     cur = new PropDir;
  301.     head = new PropPath;
  302.     tail = head;
  303.     head->element[0].dir = cur;
  304.     head->element[0].sibling = false;
  305.     if (propvalues == nil) {
  306.     propvalues = new StringPool;
  307.     }
  308. }
  309.  
  310. PropertySheet::~PropertySheet () {
  311.     register PropPath* p, * pnext;
  312.  
  313.     delete cur;
  314.     for (p = head; p != nil; p = pnext) {
  315.     pnext = p->next;
  316.     delete p;
  317.     }
  318. }
  319.  
  320. boolean PropertySheet::Get (PropertyDef& prop) {
  321.     register PropPath* p;
  322.     register PropPathElement* i;
  323.  
  324.     /* look for instance.attr */
  325.     p = tail;
  326.     i = tail->top;
  327.     if (i->dir->attrs->FindAttr(prop)) {
  328.     return true;
  329.     }
  330.     /* look for class.attr (if prev path element is class for instance) */
  331.     if (i->sibling) {
  332.     /* prev path element is class -- look for class.attr */
  333.     --i;
  334.     if (i < &p->element[0]) {
  335.         i = p->prev->top;
  336.     }
  337.     if (i->dir->attrs->FindAttr(prop)) {
  338.         return true;
  339.     }
  340.     }
  341.     /* look for path*attr */
  342.     for (p = tail; p != nil; p = p->prev) {   /* Segmentüberschreitung
  343.                                                  verhindern */
  344.     for (i = p->top; i >= &p->element[0] && (i < (i + 1)); i--) {
  345.         if (i->dir->vattrs->FindAttr(prop)) {
  346.         return true;
  347.         }
  348.     }
  349.     }
  350.     prop.value = nil;
  351.     return false;
  352. }
  353.  
  354. /*
  355.  * Special lookup under current directory for .attr  or *attr.
  356.  */
  357.  
  358. boolean PropertySheet::GetLocal (PropDir* dir, PropertyDef& prop) {
  359.     if (dir->attrs->FindAttr(prop) || dir->vattrs->FindAttr(prop)) {
  360.     return true;
  361.     }
  362.     prop.value = nil;
  363.     return false;
  364. }
  365.  
  366. /*
  367.  * Add an empty directory to the property sheet.
  368.  */
  369.  
  370. PropDir* PropertySheet::MakeDir (const char* path) {
  371.     const char* name = path;
  372.     PropDir* dir = cur;
  373.     DirList* d = (name > path && *(name-1) == '*') ? dir->vdirs : dir->dirs;
  374.     PropertyName n = nameTable->Id(name);
  375.     if (!d->FindSubDir(n, dir)) {
  376.     DirList* sub = new DirList(n);
  377.     sub->info->parent = dir;
  378.     d->Append(sub);
  379.     dir = sub->info;
  380.     }
  381.     return dir;
  382. }
  383.  
  384. /*
  385.  * Put an attribute in the property sheet, starting the path search
  386.  * at a given directory (typically the root).  If the name is already
  387.  * defined and the "override" parameter is false, then do nothing.
  388.  */
  389.  
  390. void PropertySheet::DoPut (
  391.     PropDir* root, const char* path, const char* value, const char* type,
  392.     boolean override
  393. ) {
  394.     const char* name = path;
  395.     boolean newvalue = override;
  396.     PropDir* dir = root->MakeDirs(name);
  397.     AttrList* alist =
  398.     (name > path && *(name-1) == '*') ? dir->vattrs : dir->attrs;
  399.     PropertyName n = nameTable->Id(name);
  400.     register AttrList* a = (AttrList*)alist->Find(n);
  401.     if (a == nil) {
  402.     a = new AttrList(n);
  403.     alist->Append(a);
  404.     newvalue = true;
  405.     }
  406.     if (newvalue) {
  407.     register const char* v;
  408.  
  409.     for (v = value; isspace(*v); v++);
  410.     a->value = propvalues->Append(v, strlen(v) + 1);
  411.     a->type = type;
  412.     }
  413. }
  414.  
  415. /*
  416.  * Look up the path for a subdirectory matching the given name.
  417.  */
  418.  
  419. PropDir* PropertySheet::Find (PropertyName name) {
  420.     register PropPath* p;
  421.     register PropPathElement* e;
  422.     PropDir* dir;
  423.  
  424.     dir = nil;
  425.     /* look for path.name */
  426.     if (tail->top->dir->dirs->FindSubDir(name, dir)) {
  427.     return dir;
  428.     }
  429.     /* look for path*name */
  430.     for (p = tail; p != nil; p = p->prev) {  /* Segmentüberschreitung
  431.                                                 verhindern */
  432.     for (e = p->top; e >= &p->element[0] && (e < (e + 1)); e--) {
  433.         if (e->dir->vdirs->FindSubDir(name, dir)) {
  434.         return dir;
  435.         }
  436.     }
  437.     }
  438.     return nil;
  439. }
  440.  
  441. void PropertySheet::Push (PropDir* dir, boolean b) {
  442.     register PropPath* p;
  443.     register PropPathElement* e;
  444.  
  445.     p = tail;
  446.     e = p->top + 1;
  447.     if (e >= &p->element[pathClusterSize]) {
  448.     p = new PropPath;
  449.     p->prev = tail;
  450.     tail->next = p;
  451.     tail = p;
  452.     e = p->top;
  453.     } else {
  454.     p->top = e;
  455.     }
  456.     e->dir = dir;
  457.     e->sibling = b;
  458. }
  459.  
  460. void PropertySheet::Pop () {
  461.     register PropPath* p = tail;
  462.     if (p == nil) {
  463.     /* ignore underflow */
  464.     } else if (p->top > &p->element[0]) {
  465.     p->top -= 1;
  466.     } else {
  467.     tail = p->prev;
  468.     tail->next = nil;
  469.     delete p;
  470.     }
  471. }
  472.  
  473. PropDir* PropertySheet::Root () {
  474.     return cur;
  475. }
  476.  
  477. static int line;    /* for error handling */
  478.  
  479. /*
  480.  * Load a single property from a string containing
  481.  * the name and value, terminated by either a newline or null.
  482.  */
  483.  
  484. class PropSheetBuf {
  485. public:
  486.     PropSheetBuf(int);
  487.     ~PropSheetBuf();
  488.  
  489.     char* data() { return _data; }
  490. private:
  491.     char* _data;
  492.     char _smallbuf[256];
  493. };
  494.  
  495. PropSheetBuf::PropSheetBuf(int n) {
  496.     _data = (n < sizeof(_smallbuf)) ? _smallbuf : new char[n + 1];
  497. }
  498.  
  499. PropSheetBuf::~PropSheetBuf() {
  500.     if (_data != _smallbuf) {
  501.     delete _data;
  502.     }
  503. }
  504.  
  505. void PropertySheet::LoadProperty (const char* s) {
  506.     register const char* src;
  507.     register char* dst;
  508.     const char* value;
  509.  
  510.     for (src = s; *src == ' ' || *src == '\t'; src++);
  511.     if (*src == '#' || *src == '\n' || *src == '\0') {
  512.     return;
  513.     }
  514.     PropSheetBuf buf(strlen(src));
  515.     dst = buf.data();
  516.     value = nil;
  517.     for (; *src != '\n' && *src != '\0'; src++) {
  518.     if (*src == '\\') {
  519.         ++src;
  520.         if (*src == 'n') {
  521.         *dst++ = '\n';
  522.         } else if (*src == '\n') {
  523.         ++line;
  524.         } else {
  525.         *dst++ = *src;
  526.         }
  527.     } else if (value == nil && *src == ':') {
  528.         if (dst == buf.data()) {
  529.         fprintf(stderr, "%d: empty path\n", line);
  530.         return;
  531.         }
  532.         *dst++ = '\0';
  533.         value = dst;
  534.     } else {
  535.         *dst++ = *src;
  536.     }
  537.     }
  538.     *dst = '\0';
  539.     if (value == nil) {
  540.     fprintf(stderr, "%d: missing value for %s\n", line, buf.data());
  541.     return;
  542.     }
  543.     PutLower(buf.data(), value);
  544. }
  545.  
  546. /*
  547.  * Parse property sheet information from a string.
  548.  */
  549.  
  550. void PropertySheet::LoadList (const char* data) {
  551.     register const char* p, * start;
  552.  
  553.     start = data;
  554.     for (p = strchr(data, '\n'); p != nil; p = strchr(p+1, '\n')) {
  555.     if (p > start && *(p-1) != '\\') {
  556.         LoadProperty(start);
  557.     }
  558.     start = p+1;
  559.     }
  560. }
  561.  
  562. /*
  563.  * Read a property sheet from a file (e.g., Xdefaults).
  564.  */
  565.  
  566. boolean PropertySheet::LoadFile (const char* filename) {
  567.     FILE* f;
  568.     char buf[4096];
  569.     register int i;
  570.  
  571.     if (filename == nil) {
  572.     f = stdin;
  573.     } else {
  574.     f = fopen(filename, "r");
  575.     if (f == nil) {
  576.         return false;
  577.     }
  578.     }
  579.     line = 0;
  580.     i = 0;
  581.     while (fgets(&buf[i], sizeof(buf) - i, f) != nil) {
  582.     i = strlen(buf);
  583.     if (buf[i-1] == '\n' && buf[i-2] != '\\') {
  584.         LoadProperty(buf);
  585.         i = 0;
  586.     } else {
  587.         if (i == sizeof(buf)) {
  588.         fprintf(stderr, "%s: %d: line too long\n", filename, line);
  589.         return true;
  590.         }
  591.     }
  592.     }
  593.     return true;
  594. }
  595.